﻿using Microsoft.AspNet.SignalR;
using Microsoft.SharePoint.Client;
using SharePointAccessMonitor.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security;
using System.Security.Principal;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;

namespace SharePointAccessMonitor.Controllers
{
    [System.Web.Mvc.Authorize]
    public class MonitorController : Controller
    {

        public SharePointOnlineCredentials Credentials
        {
            get { return Session["Credentials"] as SharePointOnlineCredentials; }
            set { Session["Credentials"] = value; }
        }

        public string SharePointUrl
        {
            get { return Session["SharePointUrl"] as string; }
            set { Session["SharePointUrl"] = value == null ? null : value.TrimEnd('/'); }
        }

        public string GroupName
        {
            get
            {
                return SharePointUrl.Replace("https://", "").Replace("http://", "").Replace("/", "-").Replace(".", "-");
            }
        }

        // GET: Monitor
        public ActionResult Index()
        {
            if (Credentials == null) return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
            var vm = new MainViewModel();
            using (var ctx = new ClientContext(this.SharePointUrl))
            {
                ctx.Credentials = this.Credentials;
                vm.SharePointUrl = this.SharePointUrl;
                vm.Monitoring = !string.IsNullOrWhiteSpace(GetUserScript(ctx));
            }
            return View(vm);
        }

        public ActionResult GetLog(DateTime? from, DateTime? to, int maxSize=3000)
        {
            if (Credentials == null) return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
            if (!from.HasValue) from = DateTime.Today;
            if (!to.HasValue) to = DateTime.Today.AddDays(1);
            var retDate = LogUtil.GetLog(this.GroupName, from.Value, to.Value).OrderByDescending(x => x.Timestamp).Take(maxSize).OrderBy(x => x.Timestamp).ToArray();
            return Json(retDate, JsonRequestBehavior.AllowGet);
        }

        public ActionResult Detail(string user, string filePath, string listItem, DateTime? from, DateTime? to)
        {
            if (Credentials == null) return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
            var vm = new DetailViewModel();
            var logs = new List<LogItem>();

            if (!from.HasValue) from = DateTime.Today;
            if (!to.HasValue) to = DateTime.Today.AddDays(1);

            var workLog = LogUtil.GetLog(this.GroupName, from.Value, to.Value);
            foreach (var item in workLog)
            {
                if (user != null && !user.Equals(item.User, StringComparison.InvariantCultureIgnoreCase)) continue;
                if (filePath != null && !item.GetDoumentPath().Contains(filePath)) continue;
                if (listItem != null && (item.GetListItemPath() != listItem && item.GetDisccusionPath() != listItem)) continue;
                logs.Add(item);
            }
            var keyList = new List<string>();
            if (user != null) keyList.Add(user);
            if (filePath != null) keyList.Add(filePath);
            if (listItem != null) keyList.Add(listItem);
            keyList.Add(from.Value.ToString("D") + "-" + to.Value.ToString("D"));
            vm.Keyword = string.Join(", ", keyList);            
            vm.Logs = logs;
            return View(vm);

        }

        [HttpPost]
        public ActionResult JoinGroup(string id)
        {
            var hubContext = GlobalHost.ConnectionManager.GetHubContext<MonitorHub>();
            hubContext.Groups.Add(id, this.GroupName);
            return new HttpStatusCodeResult(200);
        }

        [AllowAnonymous]
        public ActionResult Login()
        {
            return View();
        }

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Login(string spUrl, string userName, string password)
        {
            if (AuthenticateUser(spUrl, userName, password))
            {
                FormsAuthentication.SetAuthCookie(userName, false);
                return RedirectToAction("Index");
            }else
            {
                this.ModelState.AddModelError("",MessageResource.LoginAuthError);
            }
            return View();
        }

        private bool AuthenticateUser(string spUrl, string userName, string password)
        {
            var securePassword = new SecureString();
            foreach (char c in password)
            {
                securePassword.AppendChar(c);
            }
            var onlineCredentials = new SharePointOnlineCredentials(userName, securePassword);

            using (var ctx = new ClientContext(spUrl))
            {
                ctx.Credentials = onlineCredentials;
                try
                {
                    var spUser = ctx.Web.CurrentUser;
                    ctx.Load(spUser, user => user.Email, user => user.Groups);
                    ctx.ExecuteQuery();

                    GetUserScript(ctx);

                    this.Credentials = onlineCredentials;
                    this.SharePointUrl = spUrl;
                    return true;
                }
                catch (Exception)
                {
                    return false;
                }
            }

        }

        private string GetUserScript(ClientContext ctx)
        {
            var userCustomActions = ctx.Site.UserCustomActions;

            ctx.Load(userCustomActions);
            ctx.ExecuteQuery();
            var action = userCustomActions.Where(x => x.Title == userScriptName).FirstOrDefault();
            if (action == null) return null;
            return action.ScriptBlock;
        }

        private void SetUserScript(ClientContext ctx, string script)
        {
            var userCustomActions = ctx.Site.UserCustomActions;

            ctx.Load(userCustomActions);
            ctx.ExecuteQuery();
            var action = userCustomActions.Where(x => x.Title == userScriptName).FirstOrDefault();
            if (action == null)
            {
                action = userCustomActions.Add();
                action.Location = "ScriptLink";
                action.Title = userScriptName; ;
            }
            action.ScriptBlock = script ?? "";
            action.Sequence = 1000;
            action.Update();
            ctx.ExecuteQuery();

            //空の場合削除する
            if (string.IsNullOrWhiteSpace(script))
            {

                action.DeleteObject();
                ctx.Load(action);
                ctx.ExecuteQuery();
                return;
            }
        }


        private const string userScriptName = "AccessMonitor";


        public ActionResult Manage()
        {
            return View();
        }


        [HttpPost]
        public ActionResult StartMonitor()
        {
            if (Credentials == null) return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
            var actionUrl = Url.Action("Write", "Log", null, this.Request.Url.Scheme, null) + "?group=" + GroupName;
            var scriptUrl = Request.Url.Scheme + "://" + Request.Url.Authority + Url.Content("~/Scripts/splogger.js");
            var script = @"
 var s = document.createElement('script');
 s.type = 'text/javascript';
 s.src = '" + scriptUrl + @"?v=4';
 s.async = false;
 s.onload = function(){
  splogger('" + actionUrl + @"');
 };        
 document.body.appendChild(s);
";
            using (var ctx = new ClientContext(this.SharePointUrl))
            {
                ctx.Credentials = this.Credentials;
                SetUserScript(ctx, script);
            }
            return new HttpStatusCodeResult(HttpStatusCode.Accepted);
        }

        [HttpPost]
        public ActionResult StopMonitor()
        {
            if (Credentials == null) return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
            using (var ctx = new ClientContext(this.SharePointUrl))
            {
                ctx.Credentials = this.Credentials;
                SetUserScript(ctx, "");
            }
            return new HttpStatusCodeResult(HttpStatusCode.Accepted);
        }
    }
}